package com.fzsf.drawingboard.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.fzsf.drawingboard.bean.SerializablePath;
import com.fzsf.drawingboard.utils.PressureUtils;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * Created by Taijl on 2017/12/13.
 */

public class WritingBoard extends View {
    private Canvas mCanvas;
    private Paint mPaint = new Paint();
    private Paint mPaint2 = new Paint();
    private float startX;
    private float startY;
    private Bitmap mBitmap;
    private static final float STROKEWIDTH = 5f;

    public WritingBoard(Context context) {
        this(context, null);
    }

    public WritingBoard(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WritingBoard(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        initView();
    }

    private void initView() {
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.BLACK);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeWidth(STROKEWIDTH);//线宽
        mPaint.setStrokeCap(Paint.Cap.ROUND);//结束的笔画为圆心
        mPaint.setStrokeJoin(Paint.Join.ROUND);//连接处元
        mPaint.setAlpha(255);

        mPaint2.setAntiAlias(true);
        mPaint2.setColor(Color.BLACK);
        mPaint2.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint2.setStrokeWidth(2f);//线宽
        mPaint2.setAlpha(255);

        mBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(mBitmap, 0, 0, mPaint2);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                startY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                float y = event.getY();
                drawLine(startX, startY, x, y);
                startX = x;
                startY = y;
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return true;
    }

    private void drawLine(float sx, float sy, float ex, float ey) {
        mCanvas.drawLine(sx, sy, ex, ey, mPaint2);
        invalidate();
    }

    public void reSetBorad() {
        writingStartX = -1;
        writingStartY = -1;
        paths.clear();
        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
        initView();
        invalidate();
    }

    private int writingStartX = -1, writingStartY = -1;
    private boolean isWriting = false;
    private LinkedList<SerializablePath> paths = new LinkedList<>();
    /**
     * 放缩比例
     */
    private float ratio = 1f;

    public void writeByWritingPad(int x, int y, int z) {
        Log.e("writeByWritingPad ", x + " " + y + "    -->" + z);
        if (z <= 100) {
            if (isWriting) {
                penUp();
            } else {
                penDown(x, y);
            }
            return;
        }
        penMove(x, y, z);
    }

    /**
     * 书写
     *
     * @param x
     * @param y
     * @param z
     */
    private void penMove(int x, int y, int z) {
        if (null != paths && paths.size() > 0) {
            paths.getLast().addPathPoints(new float[]{x, y});
        }

        if (writingStartY != -1 && writingStartX != -1) {
            PressureUtils.addPressure(z);
            z = PressureUtils.getValidPressure();
            if (z > 1500) {
                mPaint.setAlpha(255);
                mPaint.setStrokeWidth(STROKEWIDTH);//线宽
            } else {
                mPaint.setAlpha(255 * z / 1500);
                float v = STROKEWIDTH * z / 1500;
                mPaint.setStrokeWidth(v < 1 ? 1 : v);//线宽
            }
            drawZoomLine(writingStartX, writingStartY, x, y);
            invalidate();
        }
        writingStartX = x;
        writingStartY = y;
    }

    /**
     * 抬笔
     */
    private void penUp() {
        isWriting = false;
        writingStartX = -1;
        writingStartY = -1;
        middleX = -1;
        middleY = -1;
        PressureUtils.clearPressureList();
    }

    Path path = new Path();
    float middleX = -1;
    float middleY = -1;

    private void drawZoomLine(int writingStartX, int writingStartY, float aFloat, float aFloat1) {
        float x1 = writingStartX / ratio;
        float y1 = writingStartY / ratio;
        float x2 = aFloat / ratio;
        float y2 = aFloat1 / ratio;
        if (-1 == middleX) {
            middleX = (x1 + x2) / 2;
            middleY = (y1 + y2) / 2;
            path.moveTo(x1, y1);
        } else {
            path.moveTo(middleX, middleY);
        }

        float newMiddleX = (x1 + x2) / 2;
        float newMiddleY = (y1 + y2) / 2;
        path.quadTo(x1, y1, newMiddleX, newMiddleY);
        path.close();
        mCanvas.drawPath(path, mPaint);
        path.reset();
        middleX = newMiddleX;
        middleY = newMiddleY;
    }

    /**
     * 起笔
     *
     * @param x
     * @param y
     */
    private void penDown(int x, int y) {
        paths.add(new SerializablePath());
        isWriting = true;
    }

    public void setBoardSize(int x, int y) {
        if (x != 0 && y != 0) {
            ratio = Math.max(x / getWidth(), y / getHeight());
            if (ratio < 1) {
                ratio = 1;
            }
        }
    }

    public short[] getStrokes() {
        ArrayList<Short> strokes = new ArrayList<>();
        if (null != paths && !paths.isEmpty()) {
            for (int i = 0; i < paths.size(); i++) {
                SerializablePath path = paths.get(i);
                ArrayList<float[]> pathPoints = path.getPathPoints();
                if (pathPoints.isEmpty()) {
                    continue;
                }
                for (float[] fs : pathPoints) {
                    strokes.add((short) fs[0]);
                    strokes.add((short) fs[1]);
                }
                strokes.add((short) -1);
                strokes.add((short) 0);
            }
            strokes.add((short) -1);
            strokes.add((short) -1);
        } else {
            return new short[]{};
        }
        if (!strokes.isEmpty()) {
            Short[] Shorts = new Short[strokes.size()];
            strokes.toArray(Shorts);
            short[] shorts1 = new short[strokes.size()];
            for (int i = 0; i < Shorts.length; i++) {
                shorts1[i] = Shorts[i].shortValue();
            }
            return shorts1;
        } else {
            return new short[]{};
        }
    }
}
